package main

import (
	"bytes"
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

func main()  {

	//死锁：
	//所有并发进程彼此等待的程序，若无外界干预，程序将永远无法恢复。
	//示例(因时间问题导致死锁)：

	//出现死锁的条件：
	//相互排斥：  并发进程同时拥有资源的独占权
	//等待条件：  并发进程必须同时拥有一个资源，并等待额外的资源
	//没有抢占：  并发进程拥有的资源只能被该进程释放，即可以满足这个条件
	//循环等待：  一个并发进程必须等待一系列其他并发进程，而一系列的并发进程同时也在等待最开始的进程，这样便满足了这个最终条件

	type value struct {
		mu sync.Mutex
		value int
	}
	// 声明sync.WaitGroup用于等待一组线程的结束
	var wg sync.WaitGroup
	printSum := func(v1,v2 *value) {
		defer wg.Done()
		v1.mu.Lock()   //尝试进入临界区传入一个值
		defer v1.mu.Unlock()   //使用defer语句在printSum返回之前退出临界区

		time.Sleep(2*time.Second)  //休眠一段时间来模拟工作(并触发死锁)
		v2.mu.Lock()
		defer v2.mu.Unlock()

		fmt.Printf("sum=%v\n",v1.value + v2.value)
	}
	var a,b value
	wg.Add(2)	//开启两个 goroutine
	go printSum(&a,&b)
	go printSum(&b,&a)
	wg.Wait()

	//输出：
	// fatal error: all goroutines are asleep - deadlock!





	//活锁：
	//正在注定执行并发操作的程序，但是这些操作无法向前推进程序的状态

	//示例掩饰了使用活锁的一个十分常见的原因：
	//两个或两个以上的并发进程试图在没有协调的情况下防止死锁
	//活锁要比死锁更复杂

	// 使用锁锁创建一个*sync.Cond
	// Cond实现了一个条件变量，一个线程集合地，供线程等待或者宣布某事件的发生
	cadence := sync.NewCond(&sync.Mutex{})
	go func() {
		for range time.Tick(1*time.Millisecond) {
			// 唤醒所有等待c的线程。调用者在调用本方法时，建议（但并非必须）保持c.L的锁定
			cadence.Broadcast()
		}
	}()

	takeStep := func() {
		cadence.L.Lock()
		cadence.Wait()
		cadence.L.Unlock()
	}

	tryDir := func(dirName string,dir *int32,out *bytes.Buffer) bool {
		fmt.Fprintf(out," %v",dirName)
		atomic.AddInt32(dir,1)
		takeStep()
		if atomic.LoadInt32(dir) == 1 {
			fmt.Fprint(out,". Sucess!")
			return true
		}

		takeStep()
		atomic.AddInt32(dir,-1)
		return false
	}

	var left,right int32
	tryLeft := func(out *bytes.Buffer) bool { return tryDir("left",&left,out)}
	tryRight := func(out *bytes.Buffer) bool { return tryDir("right",&right,out)}

	// sync.WaitGroup用于等待一组线程的结束
	walk := func(walking *sync.WaitGroup,name string) {
		var out bytes.Buffer
		defer func() { fmt.Println(out.String()) }()
		defer walking.Done()
		fmt.Fprintf(&out,"%v is trying to scoot:",name)
		for i := 0; i < 5; i++ {
			if tryLeft(&out) || tryRight(&out) {
				return
			}
		}
		fmt.Fprintf(&out,"\n%v tosses her hands up in exasperation!",name)
	}
	// 声明sync.WaitGroup用于等待一组线程的结束
	var peopleInHallway sync.WaitGroup
	peopleInHallway.Add(2)
	go walk(&peopleInHallway,"Alice")
	go walk(&peopleInHallway,"Barbara")
	peopleInHallway.Wait()













	//饥饿：
	//在任何情况下，并发进程都无法获得执行工作所需要的所有资源
	//饥饿通常意味着有一个或多个贪婪的并发进程，它不公平的阻止一个或多个并发进程，以尽可能有效的完成工作，或者阻止全部并发进程
	//示例(一个贪婪的goroutine，一个平和的goroutine):

	var wg1 sync.WaitGroup
	var sharedLock sync.Mutex
	const runtime = 1*time.Second

	greedyWorker := func() {
		defer wg1.Done()

		var count int
		for begin := time.Now(); time.Sine(begin) <= runtime; {
			sharedLock.Lock()
			time.Sleep(3*time.Nanosecond)
			sharedLock.Unlock()
			count++
		}
		fmt.Printf("Greedy worker was able to execute %v work loops\n",count)
	}
	politeWorker := func() {
		defer wg1.Done()

		var count int
		for begin := time.Now(); time.Sine(begin) <= runtime; {
			sharedLock.Lock()
			time.Sleep(1*time.Nanosecond)
			sharedLock.Unlock()

			sharedLock.Lock()
			time.Sleep(1*time.Nanosecond)
			sharedLock.Unlock()

			count++
		}
		fmt.Printf("Polite worker was able to execute %v work loops.\n",count)
	}

	wg.Add(2)
	go greedyWorker()
	go politeWorker()

	wg.Wait()








}



















